#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import cgi
import json
import BaseHTTPServer
import datetime
from sqlalchemy import create_engine, Table, Column, Integer, String, MetaData, ForeignKey, types
from sqlalchemy.orm import sessionmaker, mapper

CONNECTION_STRING = "postgresql://cleancity:cleanpass@localhost/cleancity"

MACROS_MARKER_COORDS = "[#MACROS_MARKER_COORDS#]"

def file_get_contents(filename):
    with open(filename) as f:
        return f.read()


class CC_Report(object):
    def __init__(self, ip, lat, lon, create_time, photo_type, photo):
        self.ip = ip
        self.lat = float(lat)
        self.lon = float(lon)
        self.create_time = create_time
        self.photo_type = photo_type
        self.photo = photo


class CC_DatabaseOperator(object):
    def __init__(self):
        engine = create_engine(CONNECTION_STRING)
        Session = sessionmaker(bind=engine)
        self.session = Session()
        metadata = MetaData(bind=engine)
        reports_table = Table('reports', metadata,
            Column('id', Integer, primary_key=True, autoincrement=True),
            Column('ip', String(15), nullable=False),
            Column('lat', types.Float),
            Column('lon', types.Float),
            Column('create_time', types.DateTime, nullable=False),
            Column('photo_type', Integer),
            Column('photo', types.LargeBinary)
        )
        mapper(CC_Report, reports_table)
        if (not reports_table.exists()):
            reports_table.create()
            print "Table `reports` created"
    
    def insert_row(self, ip, lat, lon, photo_type, photo):
        new_report = CC_Report(ip, lat, lon, datetime.datetime.now(), photo_type, photo)
        self.session.add(new_report)
        self.session.commit()
    
    def get_marker_coords_macro(self):
        macro_lat_part = "var markerLats = ["
        macro_lon_part = "var markerLons = ["
        macro_ids_part = "var markerIDs = ["
        not_empty = False
        for id, lat, lon in self.session.query(CC_Report.id, CC_Report.lat, CC_Report.lon):
            not_empty = True
            macro_lat_part += str(lat) + ", "
            macro_lon_part += str(lon) + ", "
            macro_ids_part += str(id) + ", "
        if not_empty:
            macro_lat_part = macro_lat_part[:-2]
            macro_lon_part = macro_lon_part[:-2]
            macro_ids_part = macro_ids_part[:-2]
        macro_lat_part += "]; "
        macro_lon_part += "]; "
        macro_ids_part += "];"
        return macro_lat_part + macro_lon_part + macro_ids_part
        
    def get_marker_info(self, markerID):
        exists = False
        result = "<center>"
        for ip, lat, lon, create_time, photo_type in self.session.query(CC_Report.ip, CC_Report.lat, CC_Report.lon, CC_Report.create_time, CC_Report.photo_type).filter(CC_Report.id == markerID):
            exists = True
            result += "<h2>Информация о заявке</h2></center>"
            result += "ID: " + str(markerID) + "<br />"
            result += "IP адрес: " + str(ip) + "<br />"
            result += "Координаты: lat = " + str(lat) + "; lon = " + str(lon) + "<br />"
            result += "Дата создания: " + str(create_time) + "<br />"
            result += "Тип фотографии: " + str(photo_type) + "<br />"
            result += "Фотография:<br /><a href='get_photo?" + str(markerID) + "'><img src='get_photo?" + str(markerID) + "' width=92%></a>"
        if not exists:
            result += "Информация не найдена</center>"
        return result
        
    def get_marker_photo(self, markerID):
        result = ""
        for photo in self.session.query(CC_Report.photo).filter(CC_Report.id == markerID):
            result = photo
        return result[0]


class CC_RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    # Disable reverse dns
    def address_string(self):
        host, port = self.client_address[:2]
        return host
    
    def send_response_advanced(self, code, content_type, data):
        self.send_response(code)
        self.send_header("Content-type", content_type)
        self.end_headers()
        self.wfile.write(data)
    
    def do_GET(self):
        global DB_Operator
        if self.path == '/':
            self.send_response_advanced(200, "text/html", file_get_contents("files/index_page.html").replace(MACROS_MARKER_COORDS, DB_Operator.get_marker_coords_macro(), 1))
        elif self.path == "/xmlhttp.js":
            self.send_response_advanced(200, "text/html", file_get_contents("files/xmlhttp.js"))
        elif self.path.startswith("/get_info?"):
            self.send_response_advanced(200, "text/html", DB_Operator.get_marker_info(int(self.path[10:])))
        elif self.path.startswith("/get_photo?"):
            self.send_response_advanced(200, "image/png", DB_Operator.get_marker_photo(int(self.path[11:])))
        elif self.path == '/test':
            self.send_response_advanced(200, "text/html", file_get_contents("files/test_post_page.html"))
        #elif self.path == '/favicon.ico':
        #    self.send_response_advanced(200, "image/x-icon", file_get_contents("files/favicon.ico"))
        else:
            self.send_response(404)
    
    def do_POST(self):
        global DB_Operator
        if self.path == '/upload':
            #try:
            ctype, pdict = cgi.parse_header(self.headers.getheader('content-type'))
            if ctype == 'multipart/form-data':
                multipart = cgi.parse_multipart(self.rfile, pdict)
                if ('info' in multipart) and ('file' in multipart):
                    info = json.loads(multipart['info'][0])  # coords and etc
                    DB_Operator.insert_row(self.address_string(), info[u'lat'], info[u'lon'], info[u'photo_type'], multipart['file'][0])
                    self.send_response(200)  # may be: self.send_response_advanced(200, "text/html", "OK")
                else:
                    self.send_response(400)
            else:
                self.send_response(400)
            #except:
            #    self.send_response(400)
        else:
            self.send_response(404)
    

if __name__ == "__main__":
    port = 8087
    if len(sys.argv) >= 2:
        port = int(sys.argv[1])
    print "Starting Clean City Server on port " + str(port)
    try:
        DB_Operator = CC_DatabaseOperator()
        print "DB_Operator Class Initialized"
        CC_Server = BaseHTTPServer.HTTPServer(('', port), CC_RequestHandler)
        print "CC_Server Class Initialized"
        CC_Server.serve_forever()
    except KeyboardInterrupt:
        print "\nKeyboardInterrupt received, shutting down server"
        CC_Server.socket.close()
